#!/usr/bin/env python
#coding:utf-8

import RTControl as RTC
import time
import Queue
import threading

class CylinderListener:
    def __init__(self):
        pass
    
    def OnStretch(self, axis):
        raise NotImplementedError("Method MotionListener::OnStretch not implemented.")
    
    def OnShrink(self, axis):
        raise NotImplementedError("Method MotionListener::OnShrink not implemented.")
    
    def OnStop(self, axis):
        raise NotImplementedError("Method MotionListener::OnStop not implemented.")
    
    def OnTapEnter(self, axis):
        raise NotImplementedError("Method MotionListener::OnTapEnter not implemented.")
    
    def OnTapLeave(self, axis):
        raise NotImplementedError("Method MotionListener::OnTapLeave not implemented.")
    
    def OnTimeout(self, axis):
        raise NotImplementedError("Method MotionListener::OnTimeout not implemented.")

class MyAirCylinder:
    def __init__(self, controler, v_limit1, v_limit2, v_home1, v_home2):
        self.controler = controler
        self.v_limit1 = v_limit1
        self.v_limit2 = v_limit2
        self.v_home1 = v_home1
        self.v_home2 = v_home2
        
        self.q_limit1 = Queue.Queue()
        self.q_limit2 = Queue.Queue()
        self.q_home1 = Queue.Queue()
        self.q_home2 = Queue.Queue()
        
        self.l_limit1 = threading.Lock()
        self.l_limit2 = threading.Lock()
        self.l_home1 = threading.Lock()
        self.l_home2 = threading.Lock()
        
        self.w_limit1 = False
        self.w_limit2 = False
        self.w_home1 = False
        self.w_home2 = False
        
        self._listeners = []
        
        self.v_limit1.Bind(RTC.EVT_POSITIVE_EDGE, self.OnLimit1)
        self.v_limit2.Bind(RTC.EVT_POSITIVE_EDGE, self.OnLimit2)
        self.v_home1.Bind(RTC.EVT_POSITIVE_EDGE, self.OnHome1)
        self.v_home2.Bind(RTC.EVT_POSITIVE_EDGE, self.OnHome2)
        
    def AddListener(self, listener):
        self._listeners.append(listener)
        
    def Stretch(self, timeout):
        if self.IsLimit():
            return
        self.controler.Stretch()
        try:
            self.WaitLimit1(timeout)
            self.WaitLimit2(timeout)
            self.controler.Stop()
        except:
            self.controler.Stop()
            self._OnTimeout()
            raise
        
    def Shrink(self, timeout):
        if self.IsHome():
            return
        self.controler.Shrink()
        try:
            self.WaitHome1(timeout)
            self.WaitHome2(timeout)
            self.controler.Stop()
        except:
            self.controler.Stop()
            self._OnTimeout()
            raise
        
    def Stop(self):
        self.controler.Stop()
        
    def WaitLimit1(self, timeout):
        if timeout <= 0 or self.v_limit1.GetValue():
            return
        
        with self.l_limit1:
            self.w_limit1 = True
        try:
            self.q_limit1.get(True, timeout)
            with self.l_limit1:
                self.w_limit1 = False
        except:
            with self.l_limit1:
                self.w_limit1 = False
            raise
        
    def WaitLimit2(self, timeout):
        if timeout <= 0 or self.v_limit2.GetValue():
            return
        
        with self.l_limit2:
            self.w_limit2 = True
        try:
            self.q_limit2.get(True, timeout)
            with self.l_limit2:
                self.w_limit2 = False
        except:
            with self.l_limit2:
                self.w_limit2 = False
            raise
        
    def WaitHome1(self, timeout):
        if timeout <= 0 or self.v_home1.GetValue():
            return
        
        with self.l_home1:
            self.w_home1 = True
        try:
            self.q_home1.get(True, timeout)
            with self.l_home1:
                self.w_home1 = False
        except:
            with self.l_home1:
                self.w_home1 = False
            raise
        
    def WaitHome2(self, timeout):
        if timeout <= 0 or self.v_home2.GetValue():
            return
        
        with self.l_home2:
            self.w_home2 = True
        try:
            self.q_home2.get(True, timeout)
            with self.l_home2:
                self.w_home2 = False
        except:
            with self.l_home2:
                self.w_home2 = False
            raise
        
    def OnLimit1(self, evt):
        with self.l_limit1:
            if self.w_limit1:
                self.q_limit1.put_nowait(1)
    
    def OnLimit2(self, evt):
        with self.l_limit2:
            if self.w_limit2:
                self.q_limit2.put_nowait(2)
    
    def OnHome1(self, evt):
        with self.l_home1:
            if self.w_home1:
                self.q_home1.put_nowait(3)
    
    def OnHome2(self, evt):
        with self.l_home2:
            if self.w_home2:
                self.q_home2.put_nowait(4)
            
    def IsLimit(self):
        return self.v_limit1.GetValue() and self.v_limit2.GetValue()
    
    def IsHome(self):
        return self.v_home1.GetValue() and self.v_home2.GetValue()
    
    def _OnStretch(self):
        for l in self._listeners:
            l.OnStretch(self)
    
    def _OnShrink(self):
        for l in self._listeners:
            l.OnShrink(self)
            
    def _OnStop(self):
        for l in self._listeners:
            l.OnStop(self)
    
    def _OnTapEnter(self):
        for l in self._listeners:
            l.OnTapEnter(self)
    
    def _OnTapLeave(self):
        for l in self._listeners:
            l.OnTapLeave(self)
            
    def _OnTimeout(self):
        for l in self._listeners:
            l.OnTimeout(self)